package com.ming.mallchat.common.user.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.ming.mallchat.common.chat.dao.RoomDao;
import com.ming.mallchat.common.chat.pojo.RoomFriend;
import com.ming.mallchat.common.chat.service.ChatService;
import com.ming.mallchat.common.chat.service.RoomService;
import com.ming.mallchat.common.chat.service.adapter.MessageAdapter;
import com.ming.mallchat.common.common.annotation.RedissonLock;
import com.ming.mallchat.common.common.domain.vo.req.CursorPageBaseReq;
import com.ming.mallchat.common.common.domain.vo.req.PageBaseReq;
import com.ming.mallchat.common.common.domain.vo.resp.CursorPageBaseResp;
import com.ming.mallchat.common.common.domain.vo.resp.PageBaseResp;
import com.ming.mallchat.common.common.utils.AssertUtil;
import com.ming.mallchat.common.user.dao.UserApplyDao;
import com.ming.mallchat.common.user.dao.UserDao;
import com.ming.mallchat.common.user.dao.UserFriendDao;
import com.ming.mallchat.common.user.domain.vo.req.friend.FriendApplyReq;
import com.ming.mallchat.common.user.domain.vo.req.friend.FriendApproveReq;
import com.ming.mallchat.common.user.domain.vo.req.friend.FriendCheckReq;
import com.ming.mallchat.common.user.domain.vo.resp.friend.ChatMemberResp;
import com.ming.mallchat.common.user.domain.vo.resp.friend.FriendApplyResp;
import com.ming.mallchat.common.user.domain.vo.resp.friend.FriendCheckResp;
import com.ming.mallchat.common.user.domain.vo.resp.friend.FriendUnreadResp;
import com.ming.mallchat.common.user.pojo.User;
import com.ming.mallchat.common.user.pojo.UserApply;
import com.ming.mallchat.common.user.pojo.UserFriend;
import com.ming.mallchat.common.user.service.UserFriendService;
import com.ming.mallchat.common.user.service.adpater.FriendAdapter;
import com.ming.mallchat.common.user.service.adpater.MemberAdapter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.security.auth.login.Configuration;
import java.util.*;
import java.util.stream.Collectors;

import static com.ming.mallchat.common.user.domain.enums.ApplyStatusEnum.WAIT_APPROVAL;

/**
 * @author 86150
 * @description 针对表【user_friend(用户联系人表)】的数据库操作Service实现
 * @createDate 2023-10-11 11:04:17
 */
@Service
@Slf4j
public class UserFriendServiceImpl implements UserFriendService {

    @Autowired
    private UserFriendDao userFriendDao;

    @Autowired
    private UserApplyDao userApplyDao;

    @Autowired
    private RoomService roomService;

    @Autowired
    private UserDao userDao;
    @Autowired
    private ChatService chatService;


    /**
     * 用户联系人
     *
     * @param uid 用户id
     * @param req 分页请求体
     * @return {@link CursorPageBaseResp}<{@link ChatMemberResp}>
     */
    @Override
    public CursorPageBaseResp<ChatMemberResp> friendList(Long uid, CursorPageBaseReq req) {
        CursorPageBaseResp<UserFriend> pageBaseResp = userFriendDao.getFriendList(uid, req);
        if (CollectionUtils.isEmpty(pageBaseResp.getList())) {
            return CursorPageBaseResp.empty();
        }
        List<Long> list = pageBaseResp.getList()
                .stream().map(UserFriend::getFriendUid)
                .collect(Collectors.toList());
        List<User> friendUser = userDao.getUserList(list);
        return CursorPageBaseResp.init(pageBaseResp, MemberAdapter.buildMember(pageBaseResp.getList(), friendUser));
    }

    /**
     * 批量检查是否为自己好友
     *
     * @param uid
     * @param req
     * @return {@link CursorPageBaseResp}<{@link ChatMemberResp}>
     */
    @Override
    public FriendCheckResp check(Long uid, FriendCheckReq req) {
        List<UserFriend> friendList = userFriendDao.getByFriends(uid, req.getUidList());
        Set<Long> friendSet = friendList.stream().map(UserFriend::getFriendUid).collect(Collectors.toSet());
        List<FriendCheckResp.FriendCheck> friendCheckList = req.getUidList().stream().map(userId -> {
            FriendCheckResp.FriendCheck friendCheck = new FriendCheckResp.FriendCheck();
            friendCheck.setUid(userId);
            friendCheck.setIsFriend(friendSet.contains(userId));
            return friendCheck;
        }).collect(Collectors.toList());
        return new FriendCheckResp(friendCheckList);
    }

    /**
     * 好友申请
     *
     * @param uid
     * @param request
     */
    @Override
    public void apply(Long uid, FriendApplyReq request) {
        UserFriend friend = userFriendDao.getByFriend(uid, request.getTargetUid());
        AssertUtil.isEmpty(friend, "你们已经是好友了");
        //查询自己是否已经申请了，但目标未同意
        UserApply selfUserApply = userApplyDao.getFriendApproving(uid, request.getTargetUid());
        if (Objects.nonNull(selfUserApply)) {
            log.info("已有好友申请记录,uid:{}, targetId:{}", uid, request.getTargetUid());
            return;
        }
        //是否有待审批的申请记录(别人请求自己的)
        UserApply friendApproving = userApplyDao.getFriendApproving(request.getTargetUid(), uid);
        if (Objects.nonNull(friendApproving)) {
            ((UserFriendService) AopContext.currentProxy()).applyApprove(uid, new FriendApproveReq(friendApproving.getId()));
            return;
        }
        //申请入库
        UserApply userApply = FriendAdapter.buildFriendApply(uid, request);
        userApplyDao.save(userApply);
        //TODO 推好友申请事件

    }

    /**
     * 审批好友申请
     *
     * @param uid
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "#uid")
    public void applyApprove(Long uid, FriendApproveReq request) {
        UserApply userApply = userApplyDao.getById(request.getApplyId());
        AssertUtil.isNotEmpty(userApply, "不存在申请记录");
        AssertUtil.equal(userApply.getTargetId(), uid, "不存在申请记录");
        AssertUtil.equal(userApply.getStatus(), WAIT_APPROVAL.getCode(), "已同意好友申请");
        //同意好友申请
        userApplyDao.agree(request.getApplyId());
        //创建好友关系
        createFriend(uid, userApply.getUid());
        //创建聊天房间
        RoomFriend roomFriend = roomService.createFriendRoom(Arrays.asList(uid,userApply.getUid()));
        //发送一条同意消息。我们已经是好友了，开始聊天吧
        chatService.sendMsg(MessageAdapter.buildAgreeMsg(roomFriend.getRoomId()),uid);
    }

    /**
     * 好友申请列表
     *
     * @param uid
     * @param request
     * @return {@link PageBaseResp}<{@link FriendApplyResp}>
     */
    @Override
    public PageBaseResp<FriendApplyResp> pageApplyFriend(Long uid, PageBaseReq request) {
        IPage<UserApply> userApplies = userApplyDao.friendApplyPage(uid, request.plusPageYesTotal());
        if (CollectionUtils.isEmpty(userApplies.getRecords())) {
            return PageBaseResp.empty();
        }
        //将这些申请列表设为已读
        List<Long> applyIds = userApplies.getRecords()
                .stream()
                .map(UserApply::getUid)
                .collect(Collectors.toList());
        userApplyDao.readApples(uid,applyIds);
        return PageBaseResp.init(userApplies,FriendAdapter.buildFriendApplyList(userApplies.getRecords()));
    }

    /**
     * 好友申请未读数
     *
     * @param uid
     * @return {@link FriendUnreadResp}
     */
    @Override
    public FriendUnreadResp unread(Long uid) {
        Integer count = userApplyDao.getUnreadCount(uid);
        return new FriendUnreadResp(count);
    }

    /**
     * 删除好友
     *
     * @param uid
     * @param targetUid
     */
    @Override
    public void deleteFriend(Long uid, Long targetUid) {
        List<UserFriend> userFriends = userFriendDao.getUserFriend(uid,targetUid);
        if (CollectionUtils.isEmpty(userFriends)) {
            log.info("没有好友关系：{},{}", uid, targetUid);
            return;
        }
        List<Long> list = userFriends.stream().map(UserFriend::getId).collect(Collectors.toList());
        userFriendDao.removeByIds(list);
        //TODO 禁用房间
        roomService.disableFriendRoom(Arrays.asList(uid,targetUid));
    }

    private void createFriend(Long uid, Long friendUid) {
        UserFriend userFriend1 = new UserFriend();
        userFriend1.setUid(uid);
        userFriend1.setFriendUid(friendUid);
        UserFriend userFriend2 = new UserFriend();
        userFriend2.setUid(friendUid);
        userFriend2.setFriendUid(uid);
        userFriendDao.saveBatch(Lists.newArrayList(userFriend1, userFriend2));
    }
}




